/**
 * @file form
 * @author liaoxuezhi@baidu.com
 */
/* eslint fecs-indent: [0, "space", 2, 2] */

import * as React from 'react';
import {
  Component,
  PureComponent,
  PropTypes
} from 'react';
import {Renderer, render, noop, resolveVariable, evalExpression} from '../../renderer';
import * as assign from 'object-assign';
import * as cx from 'classnames';
import * as schema from './simple-table-schema.json';

const returnFalse = () => false;

@Renderer({
  name: 'simple-table',
  desc: '...',
  test: path => !/(?:^|\/)crud\/table$/.test(path) && /(?:^|\/)table$/.test(path),
  schema,
  validateSchema: true
})
export default class SimpleTable extends Component {
  static propTypes = {
    className: PropTypes.string,
    draggable: PropTypes.bool,
    columns: PropTypes.arrayOf(PropTypes.object).isRequired,
    rows: PropTypes.oneOfType([
      PropTypes.arrayOf(PropTypes.object),
      PropTypes.string
    ])
  };

  static defaultProps = {
    className: 'table-responsive b-l b-b b-r',
    placeholder: '没有数据',
    tableClassName: 'table-db table-striped b-t b-light'
  };

  constructor(props) {
    super(props);

    this.handleLocalSort = this.handleLocalSort.bind(this);
    this.state = {
      rows: this.buildRows(props),
      columns: this.buildColumns(props),

      // 本地排序
      localOrderBy: '',
      localOrderDir: ''
    };
  }

  componentWillReceiveProps(nextProps) {
    const props = this.props;

    if (props.data !== nextProps.data || props.rows !== nextProps.rows) {
      this.setState({
        rows: this.buildRows(nextProps)
      });
    }

    if (props.data !== nextProps.data || props.columns !== nextProps.columns) {
      this.setState({
        columns: this.buildColumns(nextProps)
      });
    }
  }

  buildRows(props) {
    const {
      data,
      locals,
    } = props;
    let rows = props.rows || data.rows || [];

    if (typeof rows === 'string' && rows[0] === '$' && data) {
      rows = resolveVariable(rows, data) || resolveVariable(rows, locals) || [];
    }

    return rows;
  }

  buildColumns(props) {
    let columns = props.columns ? props.columns.concat() : [];
    const data = assign({}, props.data, {acl: {can: this.context && this.context.can || returnFalse}});

    columns = columns.filter(item => {
      if (!item) {
        return false;
      }

      return item.visibleOn
        ? evalExpression(item.visibleOn, data) : item.hiddenOn
          ? !evalExpression(item.hiddenOn, data) : true;
    });

    return columns;
  }

  handleLocalSort(name, toggle=true) {
    const {
      localOrderBy,
      localOrderDir,
      rows
    } = this.state;

    let nextLocalOrderDir = toggle ? 'asc' : localOrderDir;
    if (localOrderBy == name && toggle) {
      switch(localOrderDir) {
        case 'asc':
          nextLocalOrderDir = 'desc';
          break;
        case 'desc':
          nextLocalOrderDir = 'asc';
          break;
        default:
          nextLocalOrderDir = 'asc';
          break;
      }
    }

    if (rows) {
      rows.sort((a,b) => {
        let a1 = a[name],b1 = b[name];
        if (!isNaN(parseFloat(a1)) && !isNaN(parseFloat(b1))) {
          a1 = parseFloat(a1);
          b1 = parseFloat(b1);
        }

        if(nextLocalOrderDir == 'asc') {
          return a1 > b1 ? 1 : a1 < b1 ? -1 : 0;
        } else {
          return a1 > b1 ? -1 : a1 < b1 ? 1 : 0;
        }
      });
    }

    this.setState({
      rows: this.buildRows(assign({}, this.props, {rows})),
      localOrderDir: nextLocalOrderDir,
      localOrderBy: name
    });
  }

  renderHeading() {
    const columns = this.state.columns;
    const $path = this.props.$path;
    const {
      localOrderBy,
      localOrderDir,
    } = this.state;

    return (
      <thead>
      <tr>
        {columns.map((field, key) => render(`${$path}/heading`, assign({type: 'text'}, field), {
          key,
          sortable: false,
          localSortByName: this.handleLocalSort,
          stateLocalOrderBy: localOrderBy,
          stateLocalOrderDir: localOrderDir,
        }))}
      </tr>
      </thead>
    )
  }

  renderBody() {
    const {
      $path,
      placeholder,
      data,
      onRequestAction,
      onNotify,
      onFieldValueChange,
      onFieldValueSave,
      editIndex,
      editData
    } = this.props;
    const rows = this.state.rows;
    const columns = this.state.columns;

    return (
      <tbody>
      {rows.length ? (rows.map((item, rowIndex) => {
        const body = columns.map((field, key) => render(`${$path}/field`, assign({
          type: 'text'
        }, field), {
          key,
          $rowIndex: rowIndex,
          item: editIndex === rowIndex ? editData : item,
          value: item[field.name],
          data: assign({
            $editing: editIndex === rowIndex
          }, data, editIndex === rowIndex ? editData : item),
          onRequestAction: onRequestAction || noop,
          onFieldValueChange,
          onFieldValueSave,
          onNotify,
          disableQuickEdit: editIndex !== rowIndex || field.type === 'operation',
          elementsOnly: true,
          quickEdit: editIndex === rowIndex && field.quickEdit !== false ? assign({}, field.quickEdit, {mode: 'inline', formMode: 'normal', className: 'table-edit-inline'}) : null
        }));

        return (
          <tr
            key={rowIndex}
          >
            {body}
          </tr>
        );
      })) : (
        <tr><td colSpan={columns.length}>{placeholder}</td></tr>
      )}
      </tbody>
    );
  }


  render() {
    const {
      className,
      tableClassName
    } = this.props;


    return (
      <div className={className}>
        <table className={cx('table', tableClassName)}>
          {this.renderHeading()}
          {this.renderBody()}
        </table>
      </div>
    );
  }
}